package org.herrdommel.wakemeup.control;

import org.herrdommel.wakemeup.R;
import org.herrdommel.wakemeup.model.Alarm;
import org.herrdommel.wakemeup.provider.AlarmContentProvider;

import android.app.Activity;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
import android.support.v4.app.LoaderManager;
import android.support.v4.app.LoaderManager.LoaderCallbacks;
import android.widget.Toast;

public class AlarmController {

	private final Activity activity;
	private final LoaderManager loaderManager;
	private final ContentResolver contentResolver;

	/**
	 * Instantiates a new alarm controller.
	 * @param gui the activity that creates the controller
	 */
	public AlarmController(final Activity gui) {
		this(gui, null);
	}

	/**
	 * Instantiates a new alarm controller.
	 * @param gui the activity that creates the controller
	 * @param lm the loader manager to use
	 */
	public AlarmController(final Activity gui, final LoaderManager lm) {
		activity = gui;
		loaderManager = lm;
		contentResolver = activity.getContentResolver();
	}

	/**
	 * Returns the alarm with {@code alarmId} or a new default alarm
	 * @param alarmId the alarm id
	 * @return the alarm object or a default alarm if the one with {@code alarmId} doesn't exist
	 */
	public Alarm getAlarmById(final long alarmId) {
		if (alarmId == -1) {
			return new Alarm();
		}
		final String[] projection = {Alarm._ID, Alarm.NAME, Alarm.TIME, Alarm.IS_ACTIVE, Alarm.NEEDS_CONFIRMATION,
				Alarm.ALERT_ON_LOW_BATTERY};
		final Uri uri = Uri.withAppendedPath(AlarmContentProvider.CONTENT_URI, String.valueOf(alarmId));
		final Cursor result = contentResolver.query(uri, projection, null, null, null);
		if (result.getCount() < 1) {
			return new Alarm();
		} else {
			result.moveToPosition(0);
			return new Alarm(result);
		}
	}

	/**
	 * Handle alarm creation or updates
	 * @param alarm the new or updated alarm
	 */
	public void handleAlarmManipulation(final Alarm alarm) {
		final ContentValues values = createContentValues(alarm);
		if (alarm.getId() == -1) {
			final Uri uri = contentResolver.insert(AlarmContentProvider.CONTENT_URI, values);
			alarm.setId(Long.parseLong(uri.getLastPathSegment()));
			if (alarm.isActive()) {
				activateAlarm(alarm);
			}
		} else {
			final int rowsUpdated = contentResolver.update(
					Uri.withAppendedPath(AlarmContentProvider.CONTENT_URI, String.valueOf(alarm.getId())), values,
					null, null);
			if (rowsUpdated > 0) {
				if (alarm.isActive()) {
					activateAlarm(alarm);
				} else {
					deactivateAlarm(alarm.getId());
				}
			}
		}
	}

	/**
	 * Handle alarm deletion.
	 * @param alarmId the alarm id
	 */
	public void handleAlarmDeletion(final long alarmId) {
		handleAlarmDeletion(alarmId, null);
	}

	/**
	 * Handle alarm deletion.
	 * @param alarmId the alarm id
	 * @param lc the {@link LoaderManager.LoaderCallbacks} to use, may be null if nothing has to updated
	 */
	public void handleAlarmDeletion(final long alarmId, final LoaderCallbacks<Cursor> lc) {
		final int rowsDelete = contentResolver.delete(
				Uri.withAppendedPath(AlarmContentProvider.CONTENT_URI, String.valueOf(alarmId)), null, null);
		if (loaderManager != null && lc != null && rowsDelete > 0) {
			loaderManager.restartLoader(AlarmContentProvider.LOADER_ALARM_LIST, null, lc);
		}
		if (rowsDelete > 0) {
			deactivateAlarm(alarmId);
		}
	}

	/**
	 * Activate the alarm with {@code alarmId}
	 * @param alarmId the alarm id
	 */
	public void activateAlarm(final long alarmId) {
		final Alarm alarm = getAlarmById(alarmId);
		activateAlarm(alarm);
	}

	/**
	 * Deactivate the alarm with {@code alarmId}
	 * @param alarmId the alarm id
	 */
	public void deactivateAlarm(final long alarmId) {
		// TODO check if alarm is active
		// if alarm is active > deactivate id
	}

	/**
	 * Activate alarm.
	 * @param alarm the alarm
	 */
	private void activateAlarm(final Alarm alarm) {
		// TODO check if alarm is already active
		// if alarm is not active > activate it
		// notify user
		notifyUser(alarm);
	}

	private void notifyUser(final Alarm alarm) {
		// Calculate time between the two alarms in miliseconds
		final String toastText = String.format(activity.getString(R.string.notification_toast), alarm.getName(), "");
		Toast.makeText(activity, toastText, Toast.LENGTH_SHORT).show();
	}

	/**
	 * Creates the content values.
	 * @param alarm the alarm
	 * @return the content values
	 */
	private ContentValues createContentValues(final Alarm alarm) {
		final ContentValues values = new ContentValues();
		values.put(Alarm.NAME, alarm.getName());
		values.put(Alarm.TIME, alarm.getAlarmTime());
		values.put(Alarm.IS_ACTIVE, alarm.isActive());
		values.put(Alarm.NEEDS_CONFIRMATION, alarm.isNeedsConfirmation());
		values.put(Alarm.ALERT_ON_LOW_BATTERY, alarm.isAlertOnLowBattery());
		return values;
	}
}
